#ifndef __TEST_SYSTEM_H__
#define __TEST_SYSTEM_H__

#pragma once

#include "EngineConfig.h"

namespace Nezha
{

	class NZTest;

	typedef RefCountedPtr<NZTest>::Default NZTestPtr;

	enum TestSampleType
	{
		TST_NULL_SAMPLER,
		TST_FRAME_SAMPLER,
		TST_PEROID_SAMPLER,
		TST_COUNTED_SAMPLER
	};

	struct NEZHA_ENGINE_ENTRY NZTestSample
	{
	public:
		// time cost
		u32 Ticks;

		// memory cost
		u32 MemUsage;

		// frame count or ticks, depending on TestSampleType.
		u32 Counter;

		// sample status, if an error ocurr.
		int ErrorCode;

		// sample status, for detail query.
		int DetailInfoId;
	};

	class NEZHA_ENGINE_ENTRY NZTestSampleCollector
	{
	public:
		NZTestSampleCollector();

		~NZTestSampleCollector();

		void startCollect(TestSampleType tst, NZTest* test, u32 maxSampleNum, u32 counter);
		
		void click();

		void endCollect();

		void clear();

		u32 getNumSamples() const;

		const NZTestSample& getSample(u32 i) const;

		TestSampleType getSampleType() const
		{
			return mType;
		}

		bool getSampleCollectFinised() const;

		void reportAllSamples();

		class SampleCollection
		{
		};
	protected:
		TestSampleType mType;
		SampleCollection* mCollection;
		NZTest* mParent;
	};

	class NEZHA_ENGINE_ENTRY NZTest : public Refable
	{
		friend class TestSystem;
	public:
		virtual ~NZTest(){}

		bool initialize();

		// return true means test finished.
		bool update(float dt);

		bool reset();

		void uninitialize();

		const _string& getName() const
		{
			return mName;
		}

		bool isTesting() const
		{
			return mTesting;
		}

		virtual void setSampleCollector(bool b);

		NZTest(const _string& name)
			:mTestCounter(1)
			,mName(name)
			,mNext(NULL)
			,mTesting(false)
			,mSampler(NULL)
			,mSampleCounter(1)
			,mTimeCounter(0)
			,mSampleType(TST_COUNTED_SAMPLER)
		{
		}

		virtual void reportAllSample();

		virtual int _queryStatus(int& detailInfoId)
		{
			return 0;
		}

		void _notifySampleCollectFinished();

	protected:
		virtual bool _initialize() = 0;

		virtual bool _reset() = 0;

		virtual void _uninitialize() = 0;

		virtual bool updateImpl(float dt) = 0;

		TestSampleType mSampleType;
		NZTestSampleCollector* mSampler;
		u32 mTestCounter;
		u32 mSampleCounter;
		u32 mTimeCounter;
	private:
		_string mName;
		bool mTesting;
		NZTestPtr mNext;
	};

	class NEZHA_ENGINE_ENTRY TestFactory : public Refable
	{
	public:
		virtual NZTest* create() = 0; 

		const _string& getName() const
		{
			return mName;
		}

		TestFactory(const _string& name)
			:mName(name)
		{
		}
	protected:
		_string mName;
	};

	typedef RefCountedPtr<TestFactory>::Default TestFactoryPtr;

	template <typename T>
	class NEZHA_ENGINE_ENTRY TestFactoryTemp : public TestFactory
	{
	public:
		TestFactoryTemp(const _string& name)
			:TestFactory(name)
		{
		}

		virtual NZTest* create()
		{
			return static_cast<NZTest*>(NZ_New T(mName));
		}
	};

	class NEZHA_ENGINE_ENTRY TestSystem : public SingletonEx<TestSystem>
	{
		NEZHA_SINGLETON_DECLARE(TestSystem)
	public:
		void initializeFromCfg(const _string& fileName);

		void registerFacoty(TestFactory* fac);

		void addTest(const _string& testName, u32 testTimes = 1);

		void addTest(NZTest* t, u32 testTimes = 1);

		void update(float dt);

		// helpers
		void randomizeEnglishString(_string& str, u16 maxLen);

		// TODO profile data
		NZTestSampleCollector* getDefaultSampler()
		{
			return &mDefSampler;
		}

		TestSystem()
		{
		}
	private:
		PArray<NZTestPtr> mWaitingQueue;
		PMap<_string, TestFactoryPtr> mFacoties;
		NZTestPtr mCurrentTest;
		NZTestSampleCollector mDefSampler;
	};

}//end namespace Nezha

#endif //end __TEST_SYSTEM_H__